package com.fanrui.code.common.handle;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.ibatis.javassist.Modifier;
import org.reflections.ReflectionUtils;
import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;

import com.fanrui.code.common.annotation.Handle;
import com.fanrui.code.util.logger.Stdout;

public class HandlerMethodManager {

	private Map<Class<?>, HandlerMethod> handlers = new ConcurrentHashMap<Class<?>, HandlerMethod>();
	
	public void registe(String packageName) {
		// 找到包下面的所有类
		Reflections reflections = new Reflections(packageName, new SubTypesScanner(false));
		Set<String> allClasses = reflections.getAllTypes();
		for(String className : allClasses) {
			Class<?> clazz = ReflectionUtils.forName(className);
			if(clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) { // 忽略接口和抽象类
				continue;
			}
			Object handlerInstance = null;
			try {
				handlerInstance = clazz.newInstance();
			} catch (InstantiationException e) {
				Stdout.GET().error("类[" + className + "]无法生成实例，没有默认构造函数？", e);
				continue; // 忽略不能实例化的类
			} catch(IllegalAccessException e) {
				throw new RuntimeException(e);
			}
			Method[] methods = clazz.getMethods();
			for(Method method : methods) {
				Handle h = method.getAnnotation(Handle.class);
				if(null != h) {
					Class<?>[] parameterTypes = method.getParameterTypes();
					Class<?> commandType = parameterTypes[parameterTypes.length - 1]; // 方法的最后一个参数就是指令
					if (this.handlers.containsKey(commandType)) {
						throw new IllegalStateException("不允许重复注册HandlerMethod:" + commandType.toGenericString() + ":"
								+ method.toGenericString());
					}
					this.handlers.put(commandType, new HandlerMethod(handlerInstance, method));
				}
			}
			
		}
	}

	public Object invokeHandlerMethod(Object... args) throws InvocationTargetException {
		Class<?> commandType = args[args.length - 1].getClass(); // 方法最后一个参数，就是指令对象
		HandlerMethod handler = this.handlers.get(commandType);
		if (null == handler) {
			throw new IllegalArgumentException(String.format("没有找到 %s 对应的HandlerMethod！", commandType.getName()));
		}
		return handler.invoke(args);
	}
	
}
